home *** CD-ROM | disk | FTP | other *** search
/ CD Actual Thematic 7: Programming / CDAT7.iso / Share / Codigo / hh / rsource.exe / Hexen Source / I_CDMUS.C < prev    next >
Encoding:
C/C++ Source or Header  |  1996-01-31  |  27.5 KB  |  1,024 lines

  1.  
  2. //**************************************************************************
  3. //**
  4. //** i_cdmus.c
  5. //**
  6. //**************************************************************************
  7.  
  8. // HEADER FILES ------------------------------------------------------------
  9.  
  10. #include <stdio.h>
  11. #include <stdlib.h>
  12. #include <dos.h>
  13. #include <stddef.h>
  14. #include <string.h>
  15. #include "h2def.h"
  16. #include "i_sound.h"
  17.  
  18. // MACROS ------------------------------------------------------------------
  19.  
  20. #define MAX_AUDIO_TRACKS 25
  21. #define MULTIPLEX_INT 0x2f
  22. #define CDROM_GETDRIVECOUNT 0x1500
  23. #define CDROM_SENDDEVICEREQ 0x1510
  24. #define CDROM_GETVERSION 0x150c
  25. #define HSG_MODE 0
  26. #define RED_MODE 1
  27. #define DRC_IOCTLINPUT 0x03
  28. #define DRC_IOCTLOUTPUT 0x0c
  29. #define DRC_PLAYAUDIO 0x84
  30. #define DRC_STOPAUDIO 0x85
  31. #define DRC_RESUMEAUDIO 0x88
  32.  
  33. #define DPMI_INT 0x31
  34. #define DPMI_ALLOCREALMEM 0x0100
  35. #define DPMI_FREEREALMEM 0x0101
  36. #define DPMI_SIMREALINT 0x0300
  37.  
  38. // IOCTL input commands
  39.  
  40. #define ADRDEVHEAD       0 // Return Address of Device Header
  41. #define HEADLOCATION     1 // Location of Head
  42. #define RESERVED         2 // Reserved
  43. #define ERRSTATISTICS    3 // Error Statistics
  44. #define AUDIOCHANINFO    4 // Audio Channel Info
  45. #define READDRVBYTES     5 // Read Drive Bytes
  46. #define DEVICESTATUS     6 // Device Status
  47. #define GETSECTORSIZE    7 // Return Sector Size
  48. #define GETVOLSIZE       8 // Return Volume Size
  49. #define MEDIACHANGED     9 // Media Changed
  50. #define AUDIODISKINFO   10 // Audio Disk Info
  51. #define AUDIOTRACKINFO  11 // Audio Track Info
  52. #define AUDIOQCHANINFO  12 // Audio Q-Channel Info
  53. #define AUDIOSUBINFO    13 // Audio Sub-Channel Info
  54. #define UPCCODE         14 // UPC Code
  55. #define AUDIOSTATUSINFO 15 // Audio Status Info
  56.  
  57. // IOCTL output commands
  58.  
  59. #define EJECTDISK        0 // Eject Disk
  60. #define DOORLOCK         1 // Lock/Unlock Door
  61. #define RESETDRIVE       2 // Reset Drive
  62. #define AUDIOCHANCONTROL 3 // Audio Channel Control
  63. #define WRITEDEVCONTROL  4 // Write Device Control String
  64. #define CLOSETRAY        5 // Close Tray
  65.  
  66. // TYPES -------------------------------------------------------------------
  67.  
  68. typedef signed char        S_BYTE;
  69. typedef unsigned char    U_BYTE;
  70. typedef signed short    S_WORD;
  71. typedef unsigned short    U_WORD;
  72. typedef signed int        S_LONG;
  73. typedef unsigned int    U_LONG;
  74.  
  75. typedef struct {
  76.     U_LONG size;
  77.     void **address;
  78.     U_WORD *segment;
  79.     U_WORD *selector;
  80. } DOSChunk_t;
  81.  
  82. typedef struct {
  83.     U_LONG edi;
  84.     U_LONG esi;
  85.     U_LONG ebp;
  86.     U_LONG reserved;
  87.     U_LONG ebx;
  88.     U_LONG edx;
  89.     U_LONG ecx;
  90.     U_LONG eax;
  91.     U_WORD flags;
  92.     U_WORD es;
  93.     U_WORD ds;
  94.     U_WORD fs;
  95.     U_WORD gs;
  96.     U_WORD ip;
  97.     U_WORD cs;
  98.     U_WORD sp;
  99.     U_WORD ss;
  100. } RegBlock_t;
  101.  
  102. typedef struct {
  103.     short lengthMin;
  104.     short lengthSec;
  105.     int redStart;
  106.     int sectorStart;
  107.     int sectorLength;
  108. } AudioTrack_t;
  109.  
  110. // EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
  111.  
  112. // PUBLIC FUNCTION PROTOTYPES ----------------------------------------------
  113.  
  114. // PRIVATE FUNCTION PROTOTYPES ---------------------------------------------
  115.  
  116. static U_WORD InputIOCTL(S_WORD request, U_LONG pctrlblk);
  117. static U_WORD OutputIOCTL(S_WORD request, U_LONG pctrlblk);
  118. static U_LONG RedToSectors(U_LONG red);
  119. static int AllocIOCTLBuffers(void);
  120. static void DPMI_SimRealInt(U_LONG intr, RegBlock_t *rBlock);
  121. static void *DPMI_AllocRealMem(U_LONG size, U_WORD *segment,
  122.     U_WORD *selector);
  123. static void DPMI_FreeRealMem(U_WORD selector);
  124.  
  125. // EXTERNAL DATA DECLARATIONS ----------------------------------------------
  126.  
  127. // PUBLIC DATA DEFINITIONS -------------------------------------------------
  128.  
  129. int cd_Error;
  130.  
  131. // PRIVATE DATA DEFINITIONS ------------------------------------------------
  132.  
  133. static int cd_DriveCount;
  134. static int cd_FirstDrive;
  135. static int cd_CurDrive;
  136. static U_WORD cd_Version;
  137. static int cd_FirstTrack;
  138. static int cd_LastTrack;
  139. static int cd_TrackCount;
  140. static U_WORD cd_LeadOutMin;
  141. static U_WORD cd_LeadOutSec;
  142. static U_LONG cd_LeadOutRed;
  143. static U_LONG cd_LeadOutSector;
  144. static U_LONG cd_IOCTLBufferTotal;
  145. static AudioTrack_t cd_AudioTracks[MAX_AUDIO_TRACKS];
  146.  
  147. static int OkInit = 0;
  148.  
  149. static RegBlock_t RegBlock;
  150.  
  151. static struct PlayReq_s {       // CD-ROM Play Audio Device Request Struct
  152.     U_BYTE headerSize;
  153.     U_BYTE subUnitCode;
  154.     U_BYTE command;               // = DRC_PLAYAUDIO
  155.     U_WORD status;
  156.     U_BYTE reserved[8];
  157.     U_BYTE addressMode;
  158.     U_LONG startSector;
  159.     U_LONG numberToRead;
  160. } *cd_PlayReq;
  161. static U_WORD cd_PlayReqSeg;
  162. static U_WORD cd_PlayReqSel;
  163.  
  164. static struct StopReq_s {       // CD-ROM Stop Audio Device Request Struct
  165.     U_BYTE headerSize;
  166.     U_BYTE subUnitCode;
  167.     U_BYTE command;               // = DRC_STOPAUDIO
  168.     U_WORD status;
  169.     U_BYTE reserved[8];
  170. } *cd_StopReq;
  171. static U_WORD cd_StopReqSeg;
  172. static U_WORD cd_StopReqSel;
  173.  
  174. static struct ResumeReq_s {     // CD-ROM Resume Audio Device Request Struct
  175.     U_BYTE headerSize;
  176.     U_BYTE subUnitCode;
  177.     U_BYTE command;               // = DRC_RESUMEAUDIO
  178.     U_WORD status;
  179.     U_BYTE reserved[8];
  180. } *cd_ResumeReq;
  181. static U_WORD cd_ResumeReqSeg;
  182. static U_WORD cd_ResumeReqSel;
  183.  
  184. // IOCTL Input command data buffer structures
  185.  
  186. static struct IOCTLIn_s {       // IOCTL Input Struct
  187.     U_BYTE headerSize;
  188.     U_BYTE subUnitCode;
  189.     U_BYTE command;               // = DRC_IOCTLINPUT
  190.     U_WORD status;
  191.     U_BYTE reserved[8];
  192.     U_BYTE mediaDescriptor;
  193.     U_LONG ctrlBlkAddr;
  194.     U_WORD tranSize;
  195.     U_WORD startSector;
  196.     U_LONG volPtr;
  197. } *cd_IOCTLIn;
  198. static U_WORD cd_IOCTLInSeg;
  199. static U_WORD cd_IOCTLInSel;
  200.  
  201. static struct RAddrDevHead_s {
  202.     U_BYTE code;                  // ADRDEVHEAD
  203.     U_LONG devHdrAddr;            // Address of device header
  204. } *cd_RAddrDevHead;
  205. static U_WORD cd_RAddrDevHeadSeg;
  206. static U_WORD cd_RAddrDevHeadSel;
  207.  
  208. static struct LocHead_s {
  209.     U_BYTE code;                  // HEADLOCATION
  210.     U_BYTE addrMode;              // Addressing mode
  211.     U_LONG headLocation;          // Location of drive head
  212. } *cd_LocHead;
  213. static U_WORD cd_LocHeadSeg;
  214. static U_WORD cd_LocHeadSel;
  215.  
  216. static struct ErrStat_s {
  217.     U_BYTE code;                  // ERRSTATISTICS
  218.     U_BYTE errVal;                // Error statistics
  219. } *cd_ErrStat;
  220. static U_WORD cd_ErrStatSeg;
  221. static U_WORD cd_ErrStatSel;
  222.  
  223. static struct AudChanInfo_s {
  224.     U_BYTE code;               // AUDIOCHANINFO
  225.     U_BYTE inChanOut0;         // Input chan(0,1,2,or 3) for output chan 0
  226.     U_BYTE volumeOut0;         // Volume control (0-0xff) for output chan 0
  227.     U_BYTE inChanOut1;         // Input chan(0,1,2,or 3) for output chan 1
  228.     U_BYTE volumeOut1;         // Volume control (0-0xff) for output chan 1
  229.     U_BYTE inChanOut2;         // Input chan(0,1,2,or 3) for output chan 2
  230.     U_BYTE volumeOut2;         // Volume control (0-0xff) for output chan 2
  231.     U_BYTE inChanOut3;         // Input chan(0,1,2,or 3) for output chan 3
  232.     U_BYTE volumeOut3;         // Volume control (0-0xff) for output chan 3
  233. } *cd_AudChanInfo;
  234. static U_WORD cd_AudChanInfoSeg;
  235. static U_WORD cd_AudChanInfoSel;
  236.  
  237. static struct RDrvBytes_s {
  238.     U_BYTE code;                  // READDRVBYTES
  239.     U_BYTE numBytes;              // Number of bytes to read
  240.     U_BYTE rBuffer[128];          // Read buffer
  241. } *cd_RDrvBytes;
  242. static U_WORD cd_RDrvBytesSeg;
  243. static U_WORD cd_RDrvBytesSel;
  244.  
  245. static struct DevStat_s {
  246.     U_BYTE code;                  // DEVICESTATUS
  247.     U_LONG devParams;             // Device parameters
  248. } *cd_DevStat;
  249. static U_WORD cd_DevStatSeg;
  250. static U_WORD cd_DevStatSel;
  251.  
  252. static struct SectSize_s {
  253.     U_BYTE code;                  // GETSECTORSIZE
  254.     U_BYTE readMode;              // Read mode
  255.     U_WORD sectorSize;           // Sector size
  256. } *cd_SectSize;
  257. static U_WORD cd_SectSizeSeg;
  258. static U_WORD cd_SectSizeSel;
  259.  
  260. static struct VolSize_s {
  261.     U_BYTE code;                  // GETVOLSIZE
  262.     U_LONG volumeSize;            // Volume size
  263. } *cd_VolSize;
  264. static U_WORD cd_VolSizeSeg;
  265. static U_WORD cd_VolSizeSel;
  266.  
  267. static struct MedChng_s {
  268.     U_BYTE code;                  // MEDIACHANGED
  269.     U_BYTE changed;               // Media byte
  270. } *cd_MedChng;
  271. static U_WORD cd_MedChngSeg;
  272. static U_WORD cd_MedChngSel;
  273.  
  274. static struct DiskInfo_s {
  275.     U_BYTE code;                  // AUDIODISKINFO
  276.     U_BYTE lowTrack;              // Lowest track number
  277.     U_BYTE highTrack;             // Highest track number
  278.     U_LONG startLeadOut;          // Starting point of the lead-out track
  279. } *cd_DiskInfo;
  280. static U_WORD cd_DiskInfoSeg;
  281. static U_WORD cd_DiskInfoSel;
  282.  
  283. static struct TrackInfo_s {
  284.     U_BYTE code;                  // AUDIOTRACKINFO
  285.     U_BYTE track;                 // Track number
  286.     U_LONG start;                 // Starting point of the track
  287.     U_BYTE ctrlInfo;              // Track control information
  288. } *cd_TrackInfo;
  289. static U_WORD cd_TrackInfoSeg;
  290. static U_WORD cd_TrackInfoSel;
  291.  
  292. static struct QInfo_s {
  293.     U_BYTE code;                  // AUDIOQCHANINFO
  294.     U_BYTE control;               // CONTROL and ADR byte
  295.     U_BYTE tno;                   // Track number (TNO)
  296.     U_BYTE index;                 // (POINT) or Index(X)
  297.     U_BYTE min;                   // (MIN) Running time within a track
  298.     U_BYTE sec;                   // (SEC)    "      "    "    "   "
  299.     U_BYTE frame;                 // (FRAME)  "      "    "    "   "
  300.     U_BYTE zero;                  // (ZERO)   "      "    "    "   "
  301.     U_BYTE aMin;                  // (AMIN) or (PMIN) Running time on disk
  302.     U_BYTE aSec;                  // (ASEC) or (PSEC)    "      "   "   "
  303.     U_BYTE aFrame;                // (AFRAME) or (PFRAME)"      "   "   "
  304. } *cd_QInfo;
  305. static U_WORD cd_QInfoSeg;
  306. static U_WORD cd_QInfoSel;
  307.  
  308. static struct SubChanInfo_s {
  309.     U_BYTE code;                  // AUDIOSUBINFO
  310.     U_LONG startSectAddr;         // Starting sector address
  311.     U_LONG transAddr;             // Transfer address
  312.     U_LONG numSects;              // Number of sectors to read
  313. } *cd_SubChanInfo;
  314. static U_WORD cd_SubChanInfoSeg;
  315. static U_WORD cd_SubChanInfoSel;
  316.  
  317. static struct UPCCode_s {
  318.     U_BYTE code;                  // UPCCODE
  319.     U_BYTE control;               // CONTROL and ADR byte
  320.     U_BYTE upc[7];                // UPC/EAN code
  321.     U_BYTE zero;                  // Zero
  322.     U_BYTE aFrame;                // Aframe
  323. } *cd_UPCCode;
  324. static U_WORD cd_UPCCodeSeg;
  325. static U_WORD cd_UPCCodeSel;
  326.  
  327. static struct AudStat_s {
  328.     U_BYTE code;                  // AUDIOSTATUSINFO
  329.     U_WORD status;                // Audio status bits
  330.     U_LONG startPlay;             // Starting location of last Play/Resume
  331.     U_LONG endPlay;               // Ending location for last Play/Resume
  332. } *cd_AudStat;
  333. static U_WORD cd_AudStatSeg;
  334. static U_WORD cd_AudStatSel;
  335.  
  336. // IOCTL Output command data buffer structures
  337.  
  338. static struct IOCTLOut_s {      // IOCTL Output struct
  339.     U_BYTE headerSize;
  340.     U_BYTE subUnitCode;
  341.     U_BYTE command;               // = DRC_IOCTLOUTPUT
  342.     U_WORD status;
  343.     U_BYTE reserved[8];
  344.     U_BYTE mediaDescriptor;
  345.     U_LONG ctrlBlkAddr;
  346.     U_WORD tranSize;
  347.     U_WORD startSector;
  348.     U_LONG volPtr;
  349. } *cd_IOCTLOut;
  350. static U_WORD cd_IOCTLOutSeg;
  351. static U_WORD cd_IOCTLOutSel;
  352.  
  353. static struct Eject_s {
  354.     U_BYTE code;                  // EJECTDISK
  355. } *cd_Eject;
  356. static U_WORD cd_EjectSeg;
  357. static U_WORD cd_EjectSel;
  358.  
  359. static struct LockDoor_s {
  360.     U_BYTE code;                  // DOORLOCK
  361.     U_BYTE lock;                  // Lock function : 0 = unlock, 1 = lock
  362. } *cd_LockDoor;
  363. static U_WORD cd_LockDoorSeg;
  364. static U_WORD cd_LockDoorSel;
  365.  
  366. static struct ResetDrv_s {
  367.     U_BYTE code;                  // RESETDRIVE
  368. } *cd_ResetDrv;
  369. static U_WORD cd_ResetDrvSeg;
  370. static U_WORD cd_ResetDrvSel;
  371.  
  372. static struct AudInfo_s {
  373.     U_BYTE code;               // AUDIOCHANCONTROL
  374.     U_BYTE inChanOut0;         // Input chan(0,1,2,or 3) for output chan 0
  375.     U_BYTE volumeOut0;         // Volume control (0-0xff) for output chan 0
  376.     U_BYTE inChanOut1;         // Input chan(0,1,2,or 3) for output chan 1
  377.     U_BYTE volumeOut1;         // Volume control (0-0xff) for output chan 1
  378.     U_BYTE inChanOut2;         // Input chan(0,1,2,or 3) for output chan 2
  379.     U_BYTE volumeOut2;         // Volume control (0-0xff) for output chan 2
  380.     U_BYTE inChanOut3;         // Input chan(0,1,2,or 3) for output chan 3
  381.     U_BYTE volumeOut3;         // Volume control (0-0xff) for output chan 3
  382. } *cd_AudInfo;
  383. static U_WORD cd_AudInfoSeg;
  384. static U_WORD cd_AudInfoSel;
  385.  
  386. static struct WDrvBytes_s {
  387.     U_BYTE code;                  // WRITEDEVCONTROL
  388.     U_BYTE buf[5];                // Write buffer - size ??
  389. } *cd_WDrvBytes;
  390. static U_WORD cd_WDrvBytesSeg;
  391. static U_WORD cd_WDrvBytesSel;
  392.  
  393. static struct CloseTray_s {
  394.     U_BYTE code;                  // CLOSETRAY
  395. } *cd_CloseTray;
  396. static U_WORD cd_CloseTraySeg;
  397. static U_WORD cd_CloseTraySel;
  398.  
  399. static U_WORD InCtrlBlkSize[16] = {
  400.     0x05, 0x06, 0x00, 0x00,
  401.     0x09, 0x82, 0x05, 0x04,
  402.     0x05, 0x02, 0x07, 0x07,
  403.     0x0b, 0x0d, 0x0b, 0x0b
  404. };
  405.  
  406. static U_WORD OutCtrlBlkSize[6] = {
  407.     0x01, 0x02,
  408.     0x01, 0x09,
  409.     0x06, 0x01
  410. };
  411.  
  412. // Structures for allocating conventional memory
  413.  
  414. static DOSChunk_t DOSChunks[] = {
  415.     {
  416.         sizeof(struct PlayReq_s),
  417.         &cd_PlayReq, &cd_PlayReqSeg, &cd_PlayReqSel
  418.     },
  419.     {
  420.         sizeof(struct StopReq_s),
  421.         &cd_StopReq, &cd_StopReqSeg, &cd_StopReqSel
  422.     },
  423.     {
  424.         sizeof(struct ResumeReq_s),
  425.         &cd_ResumeReq, &cd_ResumeReqSeg, &cd_ResumeReqSel
  426.     },
  427.     {
  428.         sizeof(struct IOCTLOut_s),
  429.         &cd_IOCTLOut, &cd_IOCTLOutSeg, &cd_IOCTLOutSel
  430.     },
  431.     {
  432.         sizeof(struct Eject_s),
  433.         &cd_Eject, &cd_EjectSeg, &cd_EjectSel
  434.     },
  435.     {
  436.         sizeof(struct LockDoor_s),
  437.         &cd_LockDoor, &cd_LockDoorSeg, &cd_LockDoorSel
  438.     },
  439.     {
  440.         sizeof(struct ResetDrv_s),
  441.         &cd_ResetDrv, &cd_ResetDrvSeg, &cd_ResetDrvSel
  442.     },
  443.     {
  444.         sizeof(struct AudInfo_s),
  445.         &cd_AudInfo, &cd_AudInfoSeg, &cd_AudInfoSel
  446.     },
  447.     {
  448.         sizeof(struct WDrvBytes_s),
  449.         &cd_WDrvBytes, &cd_WDrvBytesSeg, &cd_WDrvBytesSel
  450.     },
  451.     {
  452.         sizeof(struct CloseTray_s),
  453.         &cd_CloseTray, &cd_CloseTraySeg, &cd_CloseTraySel
  454.     },
  455.     {
  456.         sizeof(struct IOCTLIn_s),
  457.         &cd_IOCTLIn, &cd_IOCTLInSeg, &cd_IOCTLInSel
  458.     },
  459.     {
  460.         sizeof(struct RAddrDevHead_s),
  461.         &cd_RAddrDevHead, &cd_RAddrDevHeadSeg, &cd_RAddrDevHeadSel
  462.     },
  463.     {
  464.         sizeof(struct LocHead_s),
  465.         &cd_LocHead, &cd_LocHeadSeg, &cd_LocHeadSel
  466.     },
  467.     {
  468.         sizeof(struct ErrStat_s),
  469.         &cd_ErrStat, &cd_ErrStatSeg, &cd_ErrStatSel
  470.     },
  471.     {
  472.         sizeof(struct AudChanInfo_s),
  473.         &cd_AudChanInfo, &cd_AudChanInfoSeg, &cd_AudChanInfoSel
  474.     },
  475.     {
  476.         sizeof(struct RDrvBytes_s),
  477.         &cd_RDrvBytes, &cd_RDrvBytesSeg, &cd_RDrvBytesSel
  478.     },
  479.     {
  480.         sizeof(struct DevStat_s),
  481.         &cd_DevStat, &cd_DevStatSeg, &cd_DevStatSel
  482.     },
  483.     {
  484.         sizeof(struct SectSize_s),
  485.         &cd_SectSize, &cd_SectSizeSeg, &cd_SectSizeSel
  486.     },
  487.     {
  488.         sizeof(struct VolSize_s),
  489.         &cd_VolSize, &cd_VolSizeSeg, &cd_VolSizeSel
  490.     },
  491.     {
  492.         sizeof(struct MedChng_s),
  493.         &cd_MedChng, &cd_MedChngSeg, &cd_MedChngSel
  494.     },
  495.     {
  496.         sizeof(struct DiskInfo_s),
  497.         &cd_DiskInfo, &cd_DiskInfoSeg, &cd_DiskInfoSel
  498.     },
  499.     {
  500.         sizeof(struct TrackInfo_s),
  501.         &cd_TrackInfo, &cd_TrackInfoSeg, &cd_TrackInfoSel
  502.     },
  503.     {
  504.         sizeof(struct QInfo_s),
  505.         &cd_QInfo, &cd_QInfoSeg, &cd_QInfoSel
  506.     },
  507.     {
  508.         sizeof(struct SubChanInfo_s),
  509.         &cd_SubChanInfo, &cd_SubChanInfoSeg, &cd_SubChanInfoSel
  510.     },
  511.     {
  512.         sizeof(struct UPCCode_s),
  513.         &cd_UPCCode, &cd_UPCCodeSeg, &cd_UPCCodeSel
  514.     },
  515.     {
  516.         sizeof(struct AudStat_s),
  517.         &cd_AudStat, &cd_AudStatSeg, &cd_AudStatSel
  518.     },
  519.     {
  520.         0, NULL, NULL, NULL
  521.     }
  522. };
  523.  
  524. // CODE --------------------------------------------------------------------
  525.  
  526. //==========================================================================
  527. //
  528. // I_CDMusInit
  529. //
  530. // Initializes the CD audio system.  Must be called before using any
  531. // other I_CDMus functions.
  532. //
  533. // Returns: 0 (ok) or -1 (error, in cd_Error).
  534. //
  535. //==========================================================================
  536.  
  537. int I_CDMusInit(void)
  538. {
  539.     int i;
  540.     int sect;
  541.     int maxTrack;
  542.     S_BYTE startMin1 = 0;
  543.     S_BYTE startSec1 = 0;
  544.     S_BYTE startMin2 = 0;
  545.     S_BYTE startSec2 = 0;
  546.     S_BYTE lengthMin = 0;
  547.     S_BYTE lengthSec = 0;
  548.  
  549.     if(OkInit != 1)
  550.     { // Only execute if uninitialized
  551.  
  552.         // Get number of CD-ROM drives and first drive
  553.         memset(&RegBlock, 0, sizeof(RegBlock));
  554.         RegBlock.eax = CDROM_GETDRIVECOUNT;
  555.         RegBlock.ebx = 0;
  556.         DPMI_SimRealInt(MULTIPLEX_INT, &RegBlock);
  557.         cd_DriveCount = RegBlock.ebx;
  558.  
  559.         // MSCDEX not installed if number of drives = 0
  560.         if(cd_DriveCount == 0)
  561.         {
  562.             cd_Error = CDERR_NOTINSTALLED;
  563.             return -1;
  564.         }
  565.         cd_FirstDrive = RegBlock.ecx;
  566.         cd_CurDrive = cd_FirstDrive;
  567.  
  568.         // Allocate the IOCTL buffers
  569.         if(AllocIOCTLBuffers() == -1)
  570.         {
  571.             cd_Error = CDERR_IOCTLBUFFMEM;
  572.             return -1;
  573.         }
  574.  
  575.         // Get MSCDEX version
  576.         // Major version in upper byte, minor version in lower byte
  577.         memset(&RegBlock, 0, sizeof(RegBlock));
  578.         RegBlock.eax = CDROM_GETVERSION;
  579.         DPMI_SimRealInt(MULTIPLEX_INT, &RegBlock);
  580.         cd_Version = RegBlock.ebx;
  581.  
  582.         // Check device status to make sure we can read Audio CD's
  583.         InputIOCTL(DEVICESTATUS, cd_DevStatSeg);
  584.         if((cd_DevStat->devParams & 0x0010) == 0)
  585.         {
  586.             cd_Error = CDERR_NOAUDIOSUPPORT;
  587.             return -1;
  588.         }
  589.     }
  590.  
  591.     // Force audio to stop playing
  592.     I_CDMusStop();
  593.  
  594.     // Make sure we have the current TOC
  595.     InputIOCTL(MEDIACHANGED, cd_MedChngSeg);
  596.  
  597.     // Set track variables
  598.     InputIOCTL(AUDIODISKINFO, cd_DiskInfoSeg);
  599.     cd_FirstTrack = cd_DiskInfo->lowTrack;
  600.     cd_LastTrack = cd_DiskInfo->highTrack;
  601.     if(cd_FirstTrack == 0 && cd_FirstTrack == cd_LastTrack)
  602.     {
  603.         cd_Error = CDERR_NOAUDIOTRACKS;
  604.         return -1;
  605.     }
  606.     cd_TrackCount = cd_LastTrack-cd_FirstTrack+1;
  607.     cd_LeadOutMin = cd_DiskInfo->startLeadOut>>16 & 0xFF;
  608.     cd_LeadOutSec = cd_DiskInfo->startLeadOut>>8 & 0xFF;
  609.     cd_LeadOutRed = cd_DiskInfo->startLeadOut;
  610.     cd_LeadOutSector = RedToSectors(cd_DiskInfo->startLeadOut);
  611.  
  612.     // Create Red Book start, sector start, and sector length
  613.     // for all tracks
  614.     sect = cd_LeadOutSector;
  615.     for(i = cd_LastTrack; i >= cd_FirstTrack; i--)
  616.     {
  617.         cd_TrackInfo->track = i;
  618.         InputIOCTL(AUDIOTRACKINFO, cd_TrackInfoSeg);
  619.         if(i < MAX_AUDIO_TRACKS)
  620.         {
  621.             cd_AudioTracks[i].redStart = cd_TrackInfo->start;
  622.             cd_AudioTracks[i].sectorStart =
  623.                 RedToSectors(cd_TrackInfo->start);
  624.             cd_AudioTracks[i].sectorLength =
  625.                 sect-RedToSectors(cd_TrackInfo->start);
  626.         }
  627.         sect = RedToSectors(cd_TrackInfo->start);
  628.     }
  629.  
  630.     // Create track lengths in minutes and seconds
  631.     if(cd_LastTrack >= MAX_AUDIO_TRACKS)
  632.     {
  633.         maxTrack = MAX_AUDIO_TRACKS-1;
  634.     }
  635.     else
  636.     {
  637.         maxTrack = cd_LastTrack;
  638.     }
  639.     cd_TrackInfo->track = cd_FirstTrack;
  640.     InputIOCTL(AUDIOTRACKINFO, cd_TrackInfoSeg);
  641.     startMin1 = (cd_TrackInfo->start >> 16);
  642.     startSec1 = (cd_TrackInfo->start >> 8);
  643.     for(i = cd_FirstTrack; i <= maxTrack; i++)
  644.     {
  645.         cd_TrackInfo->track = i+1;
  646.         if(i < cd_LastTrack)
  647.         {
  648.             InputIOCTL(AUDIOTRACKINFO, cd_TrackInfoSeg);
  649.             startMin2 = (cd_TrackInfo->start >> 16);
  650.             startSec2 = (cd_TrackInfo->start >> 8);
  651.         }
  652.         else
  653.         {
  654.             startMin2 = cd_LeadOutRed>>16;
  655.             startSec2 = cd_LeadOutRed>>8;
  656.         }
  657.         lengthSec = startSec2 - startSec1;
  658.         lengthMin = startMin2 - startMin1;
  659.         if(lengthSec < 0)
  660.         {
  661.             lengthSec += 60;
  662.             lengthMin--;
  663.         }
  664.         cd_AudioTracks[i].lengthMin = lengthMin;
  665.         cd_AudioTracks[i].lengthSec = lengthSec;
  666.         startMin1 = startMin2;
  667.         startSec1 = startSec2;
  668.     }
  669.  
  670.     // Clip high tracks
  671.     cd_LastTrack = maxTrack;
  672.  
  673.     OkInit = 1;
  674.     return 0;
  675. }
  676.  
  677. //==========================================================================
  678. //
  679. // I_CDMusPlay
  680. //
  681. // Play an audio CD track.
  682. //
  683. // Returns: 0 (ok) or -1 (error, in cd_Error).
  684. //
  685. //==========================================================================
  686.  
  687. int I_CDMusPlay(int track)
  688. {
  689.     int start;
  690.     int len;
  691.  
  692.     if(track < cd_FirstTrack || track > cd_LastTrack)
  693.     {
  694.         cd_Error = CDERR_BADTRACK;
  695.         return(-1);
  696.     }
  697.     I_CDMusStop();
  698.     start = cd_AudioTracks[track].redStart;
  699.     len = cd_AudioTracks[track].sectorLength;
  700.     cd_PlayReq->addressMode = RED_MODE;
  701.     cd_PlayReq->startSector = start;
  702.     cd_PlayReq->numberToRead = len;
  703.     memset(&RegBlock, 0, sizeof(RegBlock));
  704.     RegBlock.eax = CDROM_SENDDEVICEREQ;
  705.     RegBlock.ecx = cd_CurDrive;
  706.     RegBlock.ebx = 0;
  707.     RegBlock.es = cd_PlayReqSeg;
  708.     DPMI_SimRealInt(MULTIPLEX_INT, &RegBlock);
  709.     if(cd_PlayReq->status&0x8000)
  710.     {
  711.         cd_Error = CDERR_DEVREQBASE+(cd_PlayReq->status)&0x00ff;
  712.         return(-1);
  713.     }
  714.     return(0);
  715. }
  716.  
  717. //==========================================================================
  718. //
  719. // I_CDMusStop
  720. //
  721. // Stops the playing of an audio CD.
  722. //
  723. // Returns: 0 (ok) or -1 (error, in cd_Error).
  724. //
  725. //==========================================================================
  726.  
  727. int I_CDMusStop(void)
  728. {
  729.     memset(&RegBlock, 0, sizeof(RegBlock));
  730.     RegBlock.eax = CDROM_SENDDEVICEREQ;
  731.     RegBlock.ecx = cd_CurDrive;
  732.     RegBlock.ebx = 0;
  733.     RegBlock.es = cd_StopReqSeg;
  734.     DPMI_SimRealInt(MULTIPLEX_INT, &RegBlock);
  735.     if(cd_StopReq->status&0x8000)
  736.     {
  737.         cd_Error = CDERR_DEVREQBASE+(cd_StopReq->status)&0x00ff;
  738.         return -1;
  739.     }
  740.     return 0;
  741. }
  742.  
  743. //==========================================================================
  744. //
  745. // I_CDMusResume
  746. //
  747. // Resumes the playing of an audio CD.
  748. //
  749. // Returns: 0 (ok) or -1 (error, in cd_Error).
  750. //
  751. //==========================================================================
  752.  
  753. int I_CDMusResume(void)
  754. {
  755.     memset(&RegBlock, 0, sizeof(RegBlock));
  756.     RegBlock.eax = CDROM_SENDDEVICEREQ;
  757.     RegBlock.ecx = cd_CurDrive;
  758.     RegBlock.ebx = 0;
  759.     RegBlock.es = cd_ResumeReqSeg;
  760.     DPMI_SimRealInt(MULTIPLEX_INT, &RegBlock);
  761.     if(cd_ResumeReq->status&0x8000)
  762.     {
  763.         cd_Error = CDERR_DEVREQBASE+(cd_ResumeReq->status)&0x00ff;
  764.         return -1;
  765.     }
  766.     return 0;
  767. }
  768.  
  769. //==========================================================================
  770. //
  771. // I_CDMusSetVolume
  772. //
  773. // Sets the CD audio volume (0 - 255).
  774. //
  775. // Returns: 0 (ok) or -1 (error, in cd_Error).
  776. //
  777. //==========================================================================
  778.  
  779. int I_CDMusSetVolume(int volume)
  780. {
  781.  
  782.     if(!OkInit)
  783.     {
  784.         cd_Error = CDERR_NOTINSTALLED;
  785.            return -1;
  786.     }
  787.  
  788.     // Read current channel info
  789.     InputIOCTL(AUDIOCHANINFO, cd_AudChanInfoSeg);
  790.  
  791.     // Change the volumes
  792.     cd_AudChanInfo->volumeOut0 =
  793.         cd_AudChanInfo->volumeOut1 =
  794.         cd_AudChanInfo->volumeOut2 =
  795.         cd_AudChanInfo->volumeOut3 = volume;
  796.  
  797.     // Write modified channel info
  798.     OutputIOCTL(AUDIOCHANCONTROL, cd_AudChanInfoSeg);
  799.  
  800.     return 0;
  801. }
  802.  
  803. //==========================================================================
  804. //
  805. // I_CDMusFirstTrack
  806. //
  807. // Returns: the number of the first track.
  808. //
  809. //==========================================================================
  810.  
  811. int I_CDMusFirstTrack(void)
  812. {
  813.     return cd_FirstTrack;
  814. }
  815.  
  816. //==========================================================================
  817. //
  818. // I_CDMusLastTrack
  819. //
  820. // Returns: the number of the last track.
  821. //
  822. //==========================================================================
  823.  
  824. int I_CDMusLastTrack(void)
  825. {
  826.     return cd_LastTrack;
  827. }
  828.  
  829. //==========================================================================
  830. //
  831. // I_CDMusTrackLength
  832. //
  833. // Returns: Length of the given track in seconds, or -1 (error, in
  834. // cd_Error).
  835. //
  836. //==========================================================================
  837.  
  838. int I_CDMusTrackLength(int track)
  839. {
  840.     if(track < cd_FirstTrack || track > cd_LastTrack)
  841.     {
  842.         cd_Error = CDERR_BADTRACK;
  843.         return -1;
  844.     }
  845.     return cd_AudioTracks[track].lengthMin*60
  846.         +cd_AudioTracks[track].lengthSec;
  847. }
  848.  
  849. //==========================================================================
  850. //
  851. // AllocIOCTLBuffers
  852. //
  853. // Allocates conventional memory for the IOCTL input and output buffers.
  854. // Sets cd_IOCTLBufferTotal to the total allocated.
  855. //
  856. // Returns: 0 (ok) or -1 (error, in cd_Error).
  857. //
  858. //==========================================================================
  859.  
  860. static int AllocIOCTLBuffers(void)
  861. {
  862.     int i;
  863.     int size;
  864.     DOSChunk_t *ck;
  865.  
  866.     cd_IOCTLBufferTotal = 0;
  867.     for(i = 0; DOSChunks[i].size != 0; i++)
  868.     {
  869.         ck = &DOSChunks[i];
  870.         size = ck->size;
  871.         cd_IOCTLBufferTotal += (size+15)&0xfffffff0;
  872.         *ck->address = DPMI_AllocRealMem(size, ck->segment, ck->selector);
  873.         if(*ck->address == NULL)
  874.         {
  875.             return -1;
  876.         }
  877.         memset(*ck->address, 0, size);
  878.     }
  879.     cd_IOCTLIn->headerSize = sizeof(struct IOCTLIn_s);
  880.     cd_IOCTLIn->command = DRC_IOCTLINPUT;
  881.     cd_IOCTLOut->headerSize = sizeof(struct IOCTLOut_s);
  882.     cd_IOCTLOut->command = DRC_IOCTLOUTPUT;
  883.     cd_PlayReq->headerSize = sizeof(struct PlayReq_s);
  884.     cd_PlayReq->command = DRC_PLAYAUDIO;
  885.     cd_StopReq->headerSize = sizeof(struct StopReq_s);
  886.     cd_StopReq->command = DRC_STOPAUDIO;
  887.     cd_ResumeReq->headerSize = sizeof(struct ResumeReq_s);
  888.     cd_ResumeReq->command = DRC_RESUMEAUDIO;
  889.     return 0;
  890. }
  891.  
  892. //==========================================================================
  893. //
  894. // InputIOCTL
  895. //
  896. // Sends an IOCTL input device request command.
  897. //
  898. // Returns: the status of the request.
  899. //
  900. //==========================================================================
  901.  
  902. static U_WORD InputIOCTL(S_LONG request, U_WORD buffSeg)
  903. {
  904.     U_BYTE *code;
  905.  
  906.     code = (U_BYTE *)(buffSeg<<4);
  907.     *code = (U_BYTE)request;
  908.     cd_IOCTLIn->ctrlBlkAddr = buffSeg<<16;
  909.     cd_IOCTLIn->tranSize = InCtrlBlkSize[request];
  910.     memset(&RegBlock, 0, sizeof(RegBlock));
  911.     RegBlock.eax = CDROM_SENDDEVICEREQ;
  912.     RegBlock.ecx = cd_CurDrive;
  913.     RegBlock.ebx = 0;
  914.     RegBlock.es = cd_IOCTLInSeg;
  915.     DPMI_SimRealInt(MULTIPLEX_INT, &RegBlock);
  916.     return cd_IOCTLIn->status;
  917. }
  918.  
  919. //==========================================================================
  920. //
  921. // OutputIOCTL
  922. //
  923. // Sends an IOCTL output device request command.
  924. //
  925. // Returns: the status of the request.
  926. //
  927. //==========================================================================
  928.  
  929. static U_WORD OutputIOCTL(S_LONG request, U_WORD buffSeg)
  930. {
  931.     U_BYTE *code;
  932.  
  933.     code = (U_BYTE *)(buffSeg<<4);
  934.     *code = (U_BYTE)request;
  935.     cd_IOCTLOut->ctrlBlkAddr = buffSeg<<16;
  936.     cd_IOCTLOut->tranSize = OutCtrlBlkSize[request];
  937.     RegBlock.eax = CDROM_SENDDEVICEREQ;
  938.     RegBlock.ecx = cd_CurDrive;
  939.     RegBlock.ebx = 0;
  940.     RegBlock.es = cd_IOCTLOutSeg;
  941.     DPMI_SimRealInt(MULTIPLEX_INT, &RegBlock);
  942.     return cd_IOCTLOut->status;
  943. }
  944.  
  945. //==========================================================================
  946. //
  947. // RedToSectors
  948. //
  949. // Converts Red Book addresses to HSG sectors.
  950. // Sectors = Minutes * 60 * 75 + Seconds * 75 + Frame - 150
  951. //
  952. // Returns: HSG sectors.
  953. //
  954. //==========================================================================
  955.  
  956. static U_LONG RedToSectors(U_LONG red)
  957. {
  958.     U_LONG sector;
  959.  
  960.     sector = ((red&0x00ff0000) >> 16) * 60 * 75;
  961.     sector += ((red&0x0000ff00) >> 8) * 75;
  962.     sector += (red&0x000000ff);
  963.     return sector-150;
  964. }
  965.  
  966. //==========================================================================
  967. //
  968. // DPMI_SimRealInt
  969. //
  970. //==========================================================================
  971.  
  972. static void DPMI_SimRealInt(U_LONG intr, RegBlock_t *rBlock)
  973. {
  974.     union REGS regs;
  975.     struct SREGS sRegs;
  976.  
  977.     regs.x.eax = DPMI_SIMREALINT;
  978.     regs.x.ebx = intr;
  979.     regs.x.ecx = 0;
  980.     regs.x.edi = FP_OFF((void far *)rBlock);
  981.     sRegs.es = FP_SEG((void far *)rBlock);
  982.     sRegs.ds = FP_SEG((void far *)rBlock);
  983.     int386x(DPMI_INT, ®s, ®s, &sRegs);
  984. }
  985.  
  986. //==========================================================================
  987. //
  988. // DPMI_AllocRealMem
  989. //
  990. //==========================================================================
  991.  
  992. static void *DPMI_AllocRealMem(U_LONG size, U_WORD *segment,
  993.     U_WORD *selector)
  994. {
  995.     union REGS inRegs;
  996.     union REGS outRegs;
  997.  
  998.     inRegs.x.eax = DPMI_ALLOCREALMEM;
  999.     inRegs.x.ebx = (size+15)/16;
  1000.     int386(DPMI_INT, &inRegs, &outRegs);
  1001.     if(outRegs.x.cflag)
  1002.     {
  1003.         return NULL;
  1004.     }
  1005.     *segment = outRegs.x.eax&0xffff;
  1006.     *selector = outRegs.x.edx&0xffff;
  1007.     return (void *)(outRegs.x.eax<<4);
  1008. }
  1009.  
  1010. //==========================================================================
  1011. //
  1012. // DPMI_FreeRealMem
  1013. //
  1014. //==========================================================================
  1015.  
  1016. static void DPMI_FreeRealMem(U_WORD selector)
  1017. {
  1018.     union REGS regs;
  1019.  
  1020.     regs.x.eax = DPMI_FREEREALMEM;
  1021.     regs.x.edx = selector;
  1022.     int386(DPMI_INT, ®s, ®s);
  1023. }
  1024.